#include <cstdlib>
#include <iostream>
#include "winNetwork.h"

INetwork::~INetwork(void)
{
}

winNetwork::winNetwork(int domain, int type, int protocol, const char *ip, int port, int backlog)
: _socket(INVALID_SOCKET), _domain(domain), _type(type), _protocol(protocol), _ip(ip), _port(port), _backlog(backlog)
{
	WSADATA	data = {0};

	if (WSAStartup(MAKEWORD(2, 2), &data) != 0)
		std::cerr << "[winNetwork] Cannot initialize socket on Windows : " << WSAGetLastError() << std::endl;
}


winNetwork::winNetwork(const winNetwork &obj)
{
	this->_backlog = obj._backlog;
	this->_domain = obj._domain;
	this->_ip = obj._ip;
	this->_port = obj._port;
	this->_protocol = obj._protocol;
	this->_socket = obj._socket;
	this->_type = obj._type;
}

winNetwork::~winNetwork(void)
{
	if (this->_socket != INVALID_SOCKET)
		closeSocket();
}

winNetwork&		winNetwork::operator=(const winNetwork &obj)
{
	if (this != &obj)
	{
		this->_backlog = obj._backlog;
		this->_domain = obj._domain;
		this->_ip = obj._ip;
		this->_port = obj._port;
		this->_protocol = obj._protocol;
		this->_socket = obj._socket;
		this->_type = obj._type;
	}
	return (*this);
}

bool		winNetwork::createSocket(void)
{
	this->_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (this->_socket == INVALID_SOCKET)
	{
		std::cerr << "[WinNetwork] Cannot create socket : " << WSAGetLastError() << std::endl;
		return (false);
	}
	return (true);
}

bool		winNetwork::closeSocket(handle socket)
{
	if (socket == INVALID_SOCKET)
		socket = this->_socket;
	if (closesocket(socket) == 0)
		return (true);
	std::cerr << "WinNetwork] Cannot close socket : " << WSAGetLastError() << std::endl;
	return (false);
}

bool		winNetwork::bindNetwork(void)
{
	sockaddr_in		addr;

	addr.sin_family = this->_domain;
	addr.sin_addr.s_addr = inet_addr(this->_ip);
	addr.sin_port = htons(this->_port);
	if (bind(this->_socket, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR)
		return (true);
	std::cerr << "[winNetwork] Cannot bind socket : " << WSAGetLastError() << std::endl;
	return (false);
}

bool		winNetwork::listenNetwork(void)
{
	if (listen(this->_socket, this->_backlog) != SOCKET_ERROR)
		return (true);
	std::cerr << "[winNetwork] Cannot listen socket : " << WSAGetLastError() << std::endl;
	return (false);
}

bool		winNetwork::acceptNetwork(handle *client)
{
	sockaddr_in		addr;
	int				size = sizeof(addr);

	if (client != NULL)
		if ((*client = accept(this->_socket, (sockaddr *)&addr, &size)) != INVALID_SOCKET)
			return (true);
	std::cerr << "[winNetwork] Cannot accept socket : " << WSAGetLastError() << std::endl;
	return (false);
}

bool		winNetwork::selectNetwork(int *returnValue, int nbr, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
	if (!returnValue)
	{
		std::cerr << "[winNetwork] Select returnValue cannot be null" << std::endl;
		return (false);
	}
	if ((*returnValue = select(nbr, readfds, writefds, exceptfds, timeout)) != SOCKET_ERROR)
		return (true);
	std::cerr << "[winNetwork] Error with select : " << WSAGetLastError() << std::endl;
	return (false);
}

bool		winNetwork::initialize(void)
{
	if (this->createSocket())
		if (this->bindNetwork())
			if (this->listenNetwork())
				return (true);
	return (false);
}
